
<!DOCTYPE html>
<html>
  <head>
    
<meta charset="utf-8" >

<title>byteps 论文翻译与赏析 | dragon</title>
<meta name="description" content="邮箱(base64)：MTY5MDMwMjk2M0BxcS5jb20=
">

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css">

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="shortcut icon" href="https://dragonfive.gitee.io//favicon.ico?v=1740893463017">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0/katex.min.css">
<link rel="stylesheet" href="https://dragonfive.gitee.io//styles/main.css">



<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.1/build/highlight.min.js"></script>



  </head>
  <body>
    <div id="app" class="main">
      <div class="site-header-container">
  <div class="site-header">
    <div class="left">
      <a href="https://dragonfive.gitee.io/">
        <img class="avatar" src="https://dragonfive.gitee.io//images/avatar.png?v=1740893463017" alt="" width="32px" height="32px">
      </a>
      <a href="https://dragonfive.gitee.io/">
        <h1 class="site-title">dragon</h1>
      </a>
    </div>
    <div class="right">
      <transition name="fade">
        <i class="icon" :class="{ 'icon-close-outline': menuVisible, 'icon-menu-outline': !menuVisible }" @click="menuVisible = !menuVisible"></i>
      </transition>
    </div>
  </div>
</div>

<transition name="fade">
  <div class="menu-container" style="display: none;" v-show="menuVisible">
    <div class="menu-list">
      
        
          <a href="/" class="menu purple-link">
            首页
          </a>
        
      
        
          <a href="/archives" class="menu purple-link">
            归档
          </a>
        
      
        
          <a href="/tags" class="menu purple-link">
            标签
          </a>
        
      
        
          <a href="/post/about" class="menu purple-link">
            关于
          </a>
        
      
    </div>
  </div>
</transition>


      <div class="content-container">
        <div class="post-detail">
          
          <h2 class="post-title">byteps 论文翻译与赏析</h2>
          <div class="post-info post-detail-info">
            <span><i class="icon-calendar-outline"></i> 2021-02-17</span>
            
              <span>
                <i class="icon-pricetags-outline"></i>
                
                  <a href="https://dragonfive.gitee.io/tag/xun-lian-kuang-jia/">
                    训练框架
                    
                      ，
                    
                  </a>
                
                  <a href="https://dragonfive.gitee.io/tag/WzibKNMac/">
                    深度学习
                    
                  </a>
                
              </span>
            
          </div>
          <div class="post-content" v-pre>
            <p>byteps 代码开源在 <a href="https://github.com/bytedance/byteps">byteps repo</a>.<br>
论文地址 <a href="https://www.usenix.org/conference/osdi20/presentation/jiang">A Unified Architecture for Accelerating Distributed DNN Training in Heterogeneous GPU/CPU Clusters | USENIX</a></p>
<p>《用于在异构 GPU/CPU 集群中加速分布式 DNN 训练的统一架构》</p>
<h1 id="摘要">摘要</h1>
<p>运行 DNN 训练作业的数据中心集群本质上是异构的。 他们拥有用于计算的 GPU 和 CPU 以及用于分布式训练的网络带宽。 然而，现有的分布式 DNN 训练架构，all-reduce 和参数服务器 (PS)，无法充分利用这种异构资源。 在本文中，我们提出了一种新的分布式 DNN 训练架构，称为 BytePS。 BytePS 可以利用集群中的空闲 CPU 和带宽资源来加速在 GPU 上运行的分布式 DNN 训练任务。它提供了一个被证明是最优和统一的通信框架——现有的 all-reduce 和 PS 成为 BytePS 的两个特例。 为了在实践中实现已证明的最优性，BytePS 进一步拆分了参数优化器的功能。 它引入了用于聚合梯度的<strong>summation服务</strong>抽象，这对于所有优化器来说都是通用的。</p>
<blockquote>
<p>点评：主要的优化在于通信上。</p>
</blockquote>
<p><strong>summation服务</strong>可以通过AVX指令加速，可以在CPU上高效运行，而DNN模型相关的优化器算法在GPU上运行，进行计算加速。BytePS 可以加速主要框架的 DNN 训练，包括 TensorFlow、PyTorch 和 MXNet。 对于具有多达 256 个 GPU 的代表性 DNN 训练任务，BytePS 的性能分别比最先进的开源 all-reduce 和 PS 高出 84% 和 245%。</p>
<h1 id="1-介绍">1. 介绍</h1>
<p>近年来，深度神经网络 (DNN) 的研究经历了复兴。 DNN 为计算机视觉 、语音识别和合成 、自然语言处理 (NLP) 和许多其他领域带来了突破。 训练这些 DNN 模型通常需要大量的算术计算资源。 因此，首选 GPU。 为了运行许多此类任务并实现高资源利用率，引入了具有数千个或更多 GPU 的大型 GPU 集群。</p>
<p>这样的GPU集群不仅有GPU，还有CPU和高速网络。 GPU 机器通常也有高端 CPU。 也可能有仅 CPU 的机器用于训练数据的预处理和生成，比如在强化学习里面。这些 GPU/CPU 机器通过高速以太网或 Infiniband 网络连接，以方便分布式训练。 根据我们操作生产 GPU 集群的经验（第 3.1 节）和其他人的最新文献，通常可以更好地利用 GPU，而通常有空闲的 CPU 和带宽资源。</p>
<p>有两个主要的分布式训练架构系列，all-reduce 和参数服务器 (PS) 。 它们都基于数据并行性 。 在使用 all-reduce 的任务中，只涉及 GPU 机器。 在一次迭代中，GPU 独立计算模型参数的梯度，然后使用 all-reduce 原语聚合梯度。 在 PS 任务中，GPU 机器和 CPU 机器都可以使用。 与 all-reduce 不同的是，梯度被发送到 PS，它通常在 CPU 机器上运行并聚合接收到的梯度。然后  PS 运行某些 DNN 训练优化器，例如 SGD  或 Adam 并发回更新后的模型。 对于 all-reduce 和 PS，每次迭代都会发生上述情况，直到训练结束。</p>
<p>All-reduce 和 PS 在理论和实践上都大不相同。 给定一组没有额外 CPU 机器的 GPU 机器，经证明 all-reduce 是带宽最优的。 然而，随着 CPU 和带宽资源的增加，all-reduce 的最优性不再成立——我们发现，理论上，PS 可以通过利用额外的 CPU 机器来帮助 GPU 机器提供更好的性能。 这似乎是加速 DNN 训练的好机会，因为 GPU 集群确实有空闲的 CPU 和带宽资源。 不幸的是，在实践中，由于多种设计原因，所有现有 PS 的性能都很差，我们将在本文中很快看到。 因此看到分布式 DNN 训练速度记录以 all-reduce 为主也就不足为奇了</p>
<blockquote>
<p>点评：所有byteps 是对ps进行优化，利用好 cpu 资源</p>
</blockquote>
<p>因此，我们有动力设计 BytePS，这是一种在理论上和实践中都具有最佳通信性能的架构。 从根本上说，all-reduce 和 PS 理论上仅在非常特定的 GPU/CPU 设置中是最佳的，而对于更通用的设置则不是最佳的，例如，<strong>有一些有限的额外 CPU 资源。 通过仔细分配流量负载</strong>，BytePS 统一了 PS 或 all-reduce 理论上最优的情况，并将最优性推广到任何给定数量的具有<strong>不同 PCIe/NVLink 配置的 GPU/CPU 机器</strong>，并提供分析证明。</p>
<p>最重要的是，BytePS 通过消除现有 PS 设计中的瓶颈，将其实际性能推向接近理论极限。 对于快速的高速网络，我们发现 CPU 对于成熟的 DNN 优化器来说不够快。 我们引入了一个新的抽象，Summation Service，来解决这个问题。 我们将<strong>优化器拆分为梯度聚合和参数更新</strong>。 我们在 CPU 上运行的 <strong>Summation Service 中保持梯度聚合</strong>，并将计算密集度更高的参数更新移动到 GPU。 此外，在实施中，我们结合了先前工作中的<strong>流水线和优先级调度</strong>的想法，并解决了多个与 RDMA 相关的性能问题。</p>
<blockquote>
<p>点评：summation service 跑在cpu进行梯度聚合，因为这个是网络IO</p>
</blockquote>
<p>作为 all-reduce 和 PS 的直接替代品，BytePS 旨在在不改变 DNN 算法或其准确性的情况下加速分布式训练。 之前在 allreduce 和 PS 之上的工作，如张量压缩 ，可以直接应用于 BytePS。 我们的 BytePS 实现支持流行的 DNN 训练框架，包括 TensorFlow 、PyTorch  和 MXNet，以及类似 Horovod 的  API 和原生 API。</p>
<blockquote>
<p>点评：张量压缩的两篇论文也可以看一看[21, 45]</p>
</blockquote>
<p>本文做出以下贡献：</p>
<ul>
<li>我们为异构 GPU/CPU 集群设计了一种新的分布式 DNN 训练架构 BytePS。 借助集群中的备用 CPU 内核和网络带宽，BytePS 可以<strong>实现 DNN 训练加速的通信优化</strong>。 BytePS 提供了一个统一的框架，其中包括 all-reduce 和 PS 作为两种特殊情况。</li>
<li>我们进一步<strong>优化了机内通信</strong>。 我们解释了 GPU 机器中多样化和复杂的拓扑结构，并提出了最佳策略和原则。</li>
<li>我们提出了<strong>求和服务</strong>，它通过保持 CPU 中运行的梯度求和来加速 DNN 优化器，并将计算密集度更高的参数更新移动到 GPU。 这消除了原始 PS 设计中的 CPU 瓶颈</li>
</ul>
<p>作为主要的在线服务提供商，我们在内部部署了 BytePS，并将其广泛用于 DNN 训练。 我们在生产数据中心使用六个 DNN 模型和三个训练框架来评估 BytePS。 结果表明，使用 256 个 GPU，BytePS 始终优于现有的 allreduce 和 PS 解决方案，分别高达 84% 和 245%。 我们还发布了一个开源版本，吸引了成千上万的开源社区、几家顶级公司和多个研究小组的兴趣。</p>
<blockquote>
<p>点评：所以byteps 的主要发力点是在通信优化上</p>
</blockquote>
<h1 id="2-背景">2. 背景</h1>
<h2 id="21-分布式-dnn-训练">2.1 分布式 DNN 训练</h2>
<p>DNN 模型由许多参数组成。 DNN 训练包括三个主要步骤：（1）前向传播（FP），它接收一批训练数据，通过 DNN 模型进行传播，并计算损失函数； （2）反向传播（BP），它使用损失值来计算每个参数的梯度； (3) 参数更新，它使用聚合梯度通过某个优化器（例如，SGD、Adam 等）更新参数。 训练一个 DNN 用以上三个步骤迭代地细化模型参数，直到损失函数达到其最小值。</p>
<p>最重要的是，用户可以选择运行分布式训练。 最流行的分布式 DNN 训练方法是数据并行性，它将数据集划分到多个分布式计算设备（通常是 GPU），而每个 GPU 拥有完整的 DNN 模型。 由于每个GPU输入的数据不同，BP生成的梯度也会不同。 因此，数据并行要求所有 GPU 在每次训练迭代期间同步。</p>
<p>在大型企业或公共云中，用户经常在共享的 GPU 集群中运行这些 DNN 训练任务。 这样的集群是由成百上千的 GPU 机器构建的，这些机器通过高速 RDMA 网络连接。 这些 GPU 机器通常具有多个 GPU、数十个 CPU 内核、数百 GB 的 DRAM 和一到几个 100Gb/s NIC。 这些集群同时运行许多训练作业，其中许多作业集中使用 GPU 而不是大量使用 CPU。 DNN 集群上的公共数据集表明 50% 的主机 CPU 利用率低于 30%。</p>
<p>对于分布式训练，有两大类数据并行方法，即 all-reduce 和 Parameter Server (PS)。 下面介绍all-reduce和PS，分析它们的通信开销。 我们假设我们有 n 个 GPU 机器用于数据并行训练工作。 DNN 模型大小为 M 字节。 网络带宽为 B。</p>
<h2 id="22-all-reduce">2.2 All-reduce</h2>
<p>起源于 HPC 社区，all-reduce 在 GPU 本地更新自己的参数之前以集体的方式聚合每个 GPU 的梯度。 在 all-reduce 中，不涉及额外的 CPU 机器。 Ring 是最流行的 all-reduce 算法。 All-reduce经过多年优化，大部分最先进的训练速度记录都是使用all-reduce实现的，包括经典的基于CNN的ImageNet任务，基于RNN的语言建模任务，以及 BERT 的预训练。</p>
<p>图 1 显示了三个节点的基于环的 all-reduce 的示例。 我们可以将 all-reduce 操作分解为 <strong>reduce-scatter 和 all-gather</strong>。 Reduce-scatter（图1（a））将整个M个字节分成n个部分，并使用n个具有不同起点和终点的环分别reduce n个部分。 每个节点将发送 (n-1)M/n 个流量，因为每个节点充当仅 1 个环的最后一个节点，因此发送 0，而对于其他 n1 个环中的每一个，它必须发送 M/n 个字节。</p>
<figure data-type="image" tabindex="1"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5klx1p25j60w00a8gmy02.jpg" alt="Pasted image 20210905173924" loading="lazy"></figure>
<p>接下来，all-gather 要求每个节点使用环向所有其他 (n-1) 节点广播其减少的部分。 最后，所有节点都具有完全减少的相同数据（图 1（c））。 与reduce-scatter 类似，每个节点也在此操作期间发送(n-1)M/n 个出口流量。</p>
<p>将这两个步骤加在一起，在 all-reduce 操作中，每个节点向（和从）网络发送（和接收）2(n-1)M/n 个流量。 对于 B 网络带宽，所需时间为 2(n-1)M/nB，这在具有统一链路带宽的拓扑中被证明是最佳的，假设没有额外的资源。</p>
<p>在具有非均匀链路带宽的分层拓扑中，最佳分层策略至少需要<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>2</mn><mo>(</mo><msup><mi>n</mi><mi>l</mi></msup><mo>−</mo><mn>1</mn><mo>)</mo><mi>M</mi><mi mathvariant="normal">/</mi><msup><mi>n</mi><mi>l</mi></msup><msup><mi>B</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">2(n^l-1)M/n^lB^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.099108em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.099108em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span> 通信时间。其中<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>B</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">B^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span> 是最慢的链路带宽，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>n</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">n^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span> 是具有最慢链路的节点数。 在分布式 DNN 训练中，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>n</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">n^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span>通常是 GPU 机器的数量，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>B</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">B^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span> 通常是每台机器的网络带宽。 为简单起见且不影响我们的分析，下面我们假设每台机器只有一个 GPU，并通过相同的网络带宽连接，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>n</mi><mo>=</mo><msup><mi>n</mi><mi>l</mi></msup><mo separator="true">,</mo><mi>B</mi><mo>=</mo><msup><mi>B</mi><mi>l</mi></msup></mrow><annotation encoding="application/x-tex">n=n^l, B=B^l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.043548em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.849108em;vertical-align:0em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.849108em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span></span></span></span></span></span></span></span></span></span></span>。</p>
<p>All-reduce 无法利用额外的非工作节点，因为它是为同构设置而设计的。 接下来，我们将展示 2(n-1)M/nB 通信时间对于额外的 CPU 机器不再是最佳的。</p>
<h2 id="23-parameter-server-ps">2.3 Parameter Server (PS)</h2>
<p>PS 架构包含两个角色：worker 和 PS。 Worker 通常在 GPU 机器上运行，执行 FP 和 BP，并将梯度推送到 PS。 PS聚合来自不同worker的梯度并更新参数。 最后，worker 从 PS 中拉取最新的参数并开始下一次迭代。 根据我们的行业经验，PS 流程通常在 CPU 上运行，因为它们具有成本效益。 由于 GPU（和 GPU 内存）比 CPU 贵得多，我们希望 GPU 专注于计算密集度最高的任务，而不是存储模型参数。</p>
<p>PS有两种放置策略。 一种是非共置模式（图 2（a）），其中 PS 进程部署在专用 CPU 机器上，与 GPU 机器分开。 假设我们有 k 个 CPU 机器，DNN 模型将被分成 k 个部分并分别存储在 k 个机器上。 在每次迭代中，每个 GPU 工作人员必须发送 M 字节梯度并接收回 M 字节参数。 每台 CPU 机器必须从 GPU 工作人员处接收总共 nM/k 梯度并发送回 nM/k 参数。</p>
<p>假设 k = n，理论上 PS 将比 all-reduce 更快，如表 1 所述。实际上，PS 在这种设置下是最佳通信，因为 M 是每个 GPU 机器必须发送和接收的绝对下限。 但是，CPU 机器越少（k 越小），CPU 机器上的通信时间 nM/kB 就会增加，如果 k &lt;n/2，则变得比 all-reduce 慢。 GPU 机器的网络带宽将被利用不足，因为 CPU 机器将成为通信瓶颈。</p>
<blockquote>
<p>点评：k &lt; n/2, 通信时间就慢了</p>
</blockquote>
<p><em>表 1：每次训练迭代所需的理论通信时间。 n 是 GPU 机器的数量。 k 是附加 CPU 机器的数量。 M 是模型尺寸。 B 是网络带宽。 我们将重新审视最优</em>。<br>
<img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kn3z2jcj60xg06agmo02.jpg" alt="Pasted image 20210905184807" style="zoom:80%;" /></p>
<p>另一种策略是共置模式（图 2（b）），它不使用任何 CPU 机器。 相反，它会在每个 GPU 工作线程上启动一个 PS 进程并重用其备用 CPU 资源。 同一台机器上的 PS 和 GPU 工作器将通过环回流量（loopback traffic）进行通信。 在这种情况下，很容易计算出通信时间与all-reduce相同（表1）。</p>
<blockquote>
<p>点评：这个共置模式的提法，之前没看到过</p>
</blockquote>
<h2 id="all-reduce-vs-ps">All-reduce vs. PS.</h2>
<p>他们有不同的通信模式。 PS使用二部图。 非共置模式的 PS 可以利用额外的 CPU 和带宽资源来帮助 GPU 机器，同时可能未充分利用 GPU 机器的资源。 Colocated PS 和 all-reduce 更好地利用了 GPU Worker 资源，同时不能使用额外的 CPU 机器。</p>
<p>另一个区别是 PS 支持异步训练，它允许 GPU worker 以不同的速度运行并减轻掉队者的影响，而 all-reduce 不支持它。 但是，异步训练不太受欢迎，因为它会减慢模型收敛速度。 我们将在本文中主要关注同步训练，同时在 §5 中简要介绍异步训练。</p>
<h1 id="3-动机和-byteps-架构">3. 动机和 BytePS 架构</h1>
<h2 id="31-动机">3.1 动机</h2>
<p>在我们内部 GPU 集群中部署 BytePS 之前，我们的用户大多使用 all-reduce 作为分布式训练架构，因为它比现有的 PS 设计具有更高的性能。 其余用户选择 PS 用于异步训练可接受或更可取的任务。 凭借多年在加速 DNN 任务和提高资源利用率方面的经验和努力，我们有以下观察。</p>
<h3 id="机会">机会：</h3>
<p><strong>生产 GPU 集群中有空闲的 CPU 和带宽</strong>。</p>
<p>大规模 GPU 集群同时运行大量作业，其中许多作业不会大量使用 CPU 或网络带宽。 图 3 显示了从我们拥有数千个 GPU 的 GPU 集群之一收集的 3 个月跟踪记录。 GPU在那个时期的利用率很高（高峰期接近96%的分配率）。 我们发现，至少有 55%-80% 的 GPU 机器被分配为 GPU worker，用于至少一项分布式训练任务。 这使得 20%-45% 的 GPU 机器的网络带宽未使用，因为它们正在运行非分布式作业。集群范围内的平均 CPU 利用率仅为 20%-35% 左右。 这与 Microsoft 先前工作中的发现一致。</p>
<img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5knmkdpcj60xe0cs0uk02.jpg" alt="Pasted image 20210905192021" style="zoom:80%;" />
<p>这一观察结果与 §2.1 中的 all-reduce vs. noncolocated PS 分析相结合，启发了我们——如果我们能更好地利用这些备用 CPU 和带宽，就有可能加速在给定 GPU 上运行的分布式训练作业。</p>
<h3 id="现有的-all-reduce-和-ps-架构存在不足">现有的 all-reduce 和 PS 架构存在不足</h3>
<p>不幸的是，§2.1 中的分析也表明 all-reduce 和 PS 有一个共同的问题：它们没有很好地利用额外的 CPU 和带宽资源。 All-reduce 和 colocated PS 仅使用 GPU worker 上的资源，而非 colocated PS 可能无法充分利用 GPU worker 上的 CPU core 和 NIC 带宽。 前者仅在 k = 0 时通信最优，而后者仅在 k = n 时最优。 当 CPU 机器 k 的数量为 0 &lt; k &lt; n 时，两者都不是最优的。 我们将进一步分析放到§4.1。 在这里，我们通过一个实验来展示现有的 all-reduce 和 PS 的端到端性能。</p>
<blockquote>
<p>点评：allreduce用不了 cpu， ps 在cpu机器少的时候存在热点</p>
</blockquote>
<figure data-type="image" tabindex="2"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kok1hwcj60vs0gywhm02.jpg" alt="Pasted image 20210905221007" loading="lazy"></figure>
<p>图 4 显示了使用 32 个 V100 GPU（4 个 GPU 机器）和 100GbE RDMA 网络的 VGG-16 的训练速度。 每个 GPU 的批量大小为 32 张图像。 我们运行最新的 MXNet 原生 PS RDMA 实现 和最流行的 all-reduce 库之一的 NCCL-2.5.7 。 我们还测试了 TensorFlow 的原生 PS，并得到了类似的结果。 我们为每个设置改变了额外 CPU 机器的数量。 All-reduce 图是平坦的，因为额外的 CPU 机器没有用，而 PS 即使有额外的 CPU 机器也有最差的性能。 两者都远非最佳。 即使使用 ByteScheduler [55]，这是一种可以提高通信性能的最先进技术，但 all-reduce 和 PS 都离线性缩放还很远，即单 GPU 训练速度的 32倍。</p>
<blockquote>
<p>点评：看上去byte scheduler 调度方式，是对通信过程的流程调度。</p>
</blockquote>
<p>这是因为 ByteScheduler 工作在 PS 或 all-reduce 之上，因此具有相同的限制。 BytePS 在任何给定数量的 CPU 机器上都优于以上所有内容（更多见第 7 节）。</p>
<h3 id="我们的方案-byteps">我们的方案: BytePS.</h3>
<p>它是分布式 DNN 训练的统一架构，可以<strong>利用空闲 CPU 和带宽资源</strong>。 它实现了以下目标。</p>
<p>首先，BytePS 始终是与集群调度程序<strong>分配的任何额外 CPU 和带宽资源</strong>（即 0 &lt;= k &lt;= n）的最佳通信。 在实践中，空闲资源的数量可以是动态的（图 3），因此 BytePS 必须很好地适应。 此外，GPU 机器的硬件设置可以多种多样，尤其是内部 PCIe 或 NVLink 拓扑。 BytePS 也被证明是机器内通信的最佳选择。 All-reduce 和 PS，当它们是最佳通信时，是 BytePS（第 4 节）的两种特殊情况。</p>
<p>其次，BytePS 可以实现非常接近理论最优的通信时间。 这很重要，如现有 PS 案例所示——PS 性能远未达到其理论极限。 我们发现原始 PS 设计有几个实现瓶颈（我们将在第 6 节中讨论）。 但即使去除了所有瓶颈，PS 性能仍然不如最优。 这导致了 BytePS 的第二个设计贡献：<strong>求和服务。 我们发现在 CPU 上运行完整的优化器可能是一个瓶颈。 我们对优化器的计算进行划分，只对 CPU 进行求和</strong>。 我们将在 §5 中阐述这种设计的基本原理。</p>
<p>所有 BytePS 设计都适用于 DNN 训练。 因此，BytePS 可以加速各种 DNN 训练框架，包括 TensorFlow、PyTorch 和 MXNet。 我们从介绍 BytePS 的架构开始。</p>
<h2 id="32-架构概述">3.2 架构概述</h2>
<figure data-type="image" tabindex="3"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kp2m9xzj60x40dcq4z02.jpg" alt="Pasted image 20210905223306" loading="lazy"></figure>
<p><em>图 5：BytePS 架构。 实线：CPU 机器和 GPU 机器之间的连接。 虚线：GPU 机器内部的数据流。</em></p>
<p>图 5 显示了 BytePS 的架构。 BytePS 有两个主要模块——通信服务（CS）和求和服务（SS）。 在 BytePS 中，我们旨在利用任何 CPU 资源，无论是在 GPU 机器上还是 CPU 机器上，以实现最佳通信效率。 这是由 SS 实现的，它运行在每台机器的 CPU 上，包括 CPU 机器和 GPU 机器。 CPU 机器不一定是实际的仅使用 CPU 的机器。 例如，我们的内部集群调度程序可以在运行非分布式作业并具有备用 CPU 内核和网络带宽的 GPU 机器上分配 CPU。 这提高了整体集群资源利用率。</p>
<p>SS 的另一个重要特性是它比运行成熟 DNN 算法优化器的常见 PS 服务器进程简单得多。 相比之下，SS 只负责接收 CS 发送的张量，将张量汇总并发送回 CS。 <strong>另一个模块 CS 负责在多个（如果有）本地 GPU 之间内部同步张量，并与 SS 进行外部通信</strong>。 每次训练迭代，每个 CS 必须向 SS 发送总共 M 个字节（DNN 模型大小）并从 SS 接收 M 个字节。 在同步分布式训练中，张量是模型梯度。</p>
<blockquote>
<p>点评：cs 负责gpu间同步</p>
</blockquote>
<p>CS 包含了 BytePS 的几个设计点。 首先，它决定每个 SS（内部和外部）的流量。 负载分配策略基于我们对最佳通信策略的分析（第 4.1 节）。 其次，它根据 GPU 机器的不同内部 GPU 和 NIC 拓扑（第 4.2 节）选择最佳的局部张量聚合策略。 最后，CS 和 SS 都应针对现代高速数据中心中的 RDMA 进行优化（第 6.2 节）。</p>
<blockquote>
<p>点评：所以有几个关键点：负载均衡通信策略，张量聚合策略，RDMA优化，cs 和 ss 和交互</p>
</blockquote>
<p>这种架构使 BytePS 能够灵活地利用任意数量的额外 CPU 资源和网络带宽。 当 CPU 机器数为 0 时，即 k = 0，通信将回退到仅在 GPU 机器上使用 SS。 当 CPU 机器数与 GPU 机器数相同时，BytePS 与非 colocated PS 的通信最佳。 在其他情况下，BytePS 可以同时利用所有机器上的 SS。 事实上，我们的分析结果将揭示与任意数量的 CPU 机器的最佳通信策略，而 PS 和 all-reduce 只是整个问题空间中的两个特定点。</p>
<blockquote>
<p>点评：其实就是借用gpu机器上的cpu，来达到最优ps数量</p>
</blockquote>
<h1 id="4-byteps-通信设计">4. BytePS 通信设计</h1>
<h2 id="41-机器间通信">4.1 机器间通信</h2>
<p>在 BytePS 中，所有的网络通信都是在 CS 和 SS 之间进行的。 为了防止瓶颈节点拖慢整个系统，我们必须平衡所有机器的通信时间。 在下文中，我们假设网络具有完整的二分带宽，这是深度学习集群中的常见做法。 我们还假设由于新引入的 RDMA 拥塞控制算法，例如 DCQCN，可以充分利用完整的二分带宽。</p>
<blockquote>
<p>点评：所以 byteps 依赖 rdma 的gpu 集群</p>
</blockquote>
<p>在每台 CPU 机器上，其 SS 的工作负载总和决定了网络流量。 例如，如果一个 SS 负责汇总 x% 的 DNN 模型，则 CPU 机器将在每次训练迭代期间向每台 GPU 机器发送和接收 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>x</mi><mi mathvariant="normal">%</mi><mi>M</mi></mrow><annotation encoding="application/x-tex">x \% M</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.80556em;vertical-align:-0.05556em;"></span><span class="mord mathdefault">x</span><span class="mord">%</span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span></span></span></span> 字节的流量。 但是，GPU 机器的网络流量是由其上运行的 CS 和 SS 的组合决定的。 由于这种差异，BytePS根据是运行在CPU机器还是GPU机器上将SS分为SSCPU和SSGPU。</p>
<p>为了最小化通信时间，BytePS 将 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{CPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 字节总和工作负载分配给每个 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow><annotation encoding="application/x-tex">SS_{CPU}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 。  <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{CPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 在方程式1中给出。 其中 k &lt;= 1 是 CPU 机器的数量，n &lt;= 2 是 GPU 机器的数量，k &lt;= n。 在这些限制之外，BytePS 的通信时间回退到像 PS（当 k &gt; n）和 all-reduce（当 k = 0）这样的简单解决方案，如 §4.1.1 所示。</p>
<img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kpjgf9lj60o203yq2z02.jpg" alt="Pasted image 20210906105230" style="zoom:80%;" />
<p>类似地，BytePS 将 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 字节分配给每个 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow><annotation encoding="application/x-tex">SS_{GPU}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 。</p>
<figure data-type="image" tabindex="4"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kq12up8j60oq04kmx602.jpg" alt="Pasted image 20210906105725" loading="lazy"></figure>
<p>等式 1 和等式 2 显示了最适合最小化通信时间的工作负载分配策略。 分析在 §4.1.1 中。 在实践中，DNN 模型由大小可变的张量组成，可能无法让我们完美地分配工作负载。 BytePS 使用近似方法。 它将张量分成不大于 4MB 的小部分。然后，所有 CS 一致地索引每个部分并将索引散列到 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>[</mo><mn>0</mn><mo separator="true">,</mo><msup><mi>n</mi><mn>2</mn></msup><mo>+</mo><mi>k</mi><mi>n</mi><mo>−</mo><mn>2</mn><mi>k</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">[0,n^2+kn-2k)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mopen">[</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathdefault" style="margin-right:0.03148em;">k</span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mord mathdefault" style="margin-right:0.03148em;">k</span><span class="mclose">)</span></span></span></span> 的范围内。 CS 将根据散列值向 SS 发送和接收张量，并根据等式 1 和等式 2 估算概率。一致的索引和散列保证来自所有 GPU 的相同部分将被发送到同一个 SS 并由其处理。</p>
<blockquote>
<p>我们发现 4MB 分区大小在我们的环境中运行良好，但 BytePS 允许用户调整分区大小值。</p>
</blockquote>
<blockquote>
<p>点评：tensor切分小块，索引按什么顺序索引呢，如果是稀疏的场景该怎么办呢</p>
</blockquote>
<h3 id="411-通信效率分析">4.1.1 通信效率分析</h3>
<p>接下来，我们介绍BytePS的通信时间分析。 为了简化分析，我们假设模型大小 M 远大于分区大小（在我们的例子中为 4MB）。 分区使 BytePS 不仅可以更好地平衡求和工作负载，还可以通过流水线发送和接收来很好地利用双向网络带宽，如 [34, 55] 所示。 因此，我们进一步假设发送和接收整个 M 字节可以完全重叠，开销可以忽略不计。 我们有以下结果。</p>
<p><strong>推理 1</strong>. 等式 1 和等式 2 给出的 SS 工作负载分配对于最小化通信时间是最佳的。</p>
<p>证明。 我们首先考虑 GPU 机器的网络流量。 它运行一个 CS 模块和一个 SS 模块。 CS 总共应该发送和接收 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi></mrow><annotation encoding="application/x-tex">M</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span></span></span></span> 个字节。 但是，当它与同一 GPU 机器上的 SS 通信时，流量不会通过网络。 因此，CS 模块将发送和接收 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi><mo>−</mo><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M-M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 个字节。 GPU机器上的SS模块必须从其他<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">n-1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span>个GPU机器接收和发送<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span>, 总共 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>(</mo><mi>n</mi><mo>−</mo><mn>1</mn><mo>)</mo><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">(n-1)M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.000305em;vertical-align:-0.250305em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 。将它们加在一起，网络带宽为 B 的 GPU 机器需要通信时间 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">t_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9011879999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>：</p>
<figure data-type="image" tabindex="5"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kzkcgx3j60oo04s74b02.jpg" alt="Pasted image 20210906121509" loading="lazy"></figure>
<p>同样，如果 k &gt; 0，我们可以得到网络带宽为 B 的 CPU 机器需要通信时间 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>c</mi></msub></mrow><annotation encoding="application/x-tex">t_c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>：</p>
<p class='katex-block'><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>c</mi></msub><mo>=</mo><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub><mi mathvariant="normal">/</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">t_c = M_{SS_{CPU}}/B
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.000305em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span></p>
<p>此外，所有 SS 工作量的总和应等于总模型大小。</p>
<p class='katex-block'><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi><mo>=</mo><mi>k</mi><msub><mi>M</mi><mrow><mi>S</mi><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></mrow></msub><mo>+</mo><mi>n</mi><msub><mi>M</mi><mrow><mi>S</mi><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></mrow></msub></mrow><annotation encoding="application/x-tex">M = kM_{SS{CPU}} +nM_{SS{GPU}}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.03148em;">k</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault">n</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span></p>
<p>从方程 5 可以看出，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{CPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 越大，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 越小。 因此，当 n 2 时，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>c</mi></msub></mrow><annotation encoding="application/x-tex">t_c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 越大，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">t_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9011879999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>  越小（或者如果 n = 2，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>t</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">t_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9011879999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>  不变）。 另外，我们知道最终的通信时间是<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>m</mi><mi>a</mi><mi>x</mi><mo>(</mo><msub><mi>t</mi><mi>c</mi></msub><mo separator="true">,</mo><msub><mi>t</mi><mi>g</mi></msub><mo>)</mo></mrow><annotation encoding="application/x-tex">max(t_c ,t_g)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord mathdefault">m</span><span class="mord mathdefault">a</span><span class="mord mathdefault">x</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>。</p>
<p>为了最小化通信时间，tc 和 tg 需要相等。 如果它们不相等，例如 tc &gt; tg，则意味着可以通过减少 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>C</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{CPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.07153em;">C</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> 进一步减少通信时间，从而降低 tc。</p>
<p>当 CPU 机器和 GPU 机器的数量相同时， <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>M</mi><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">M_{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.933635em;vertical-align:-0.250305em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.3567071428571427em;margin-left:-0.05764em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.14329285714285717em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.250305em;"><span></span></span></span></span></span></span></span></span></span> = 0，这意味着我们不需要任何 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>S</mi><msub><mi>S</mi><mrow><mi>G</mi><mi>P</mi><mi>U</mi></mrow></msub></mrow><annotation encoding="application/x-tex">{SS_{GPU}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">G</span><span class="mord mathdefault mtight" style="margin-right:0.13889em;">P</span><span class="mord mathdefault mtight" style="margin-right:0.10903em;">U</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span> 。 这是因为 CPU 机器已经提供了足够的聚合带宽。 BytePS 回退到非共放置PS。 同样，当CPU机器数为0时，BytePS回退到all-reduce和colocated PS。</p>
<p>当然，更有趣的情况是当 0 &lt; k &lt; n 时的一般情况。 我们使用普通的 all-reduce 和 non-colocated PS 的通信时间作为两个基线。 我们将加速比 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>r</mi><mi>a</mi></msub></mrow><annotation encoding="application/x-tex">r_a</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 定义为普通 all-reduce 的通信时间除以一般情况的通信时间。 类似地，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>r</mi><mi>p</mi></msub></mrow><annotation encoding="application/x-tex">r_p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> 被定义为与非同位 PS 情况相比的加速比。 我们有以下结论</p>
<figure data-type="image" tabindex="6"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kqkapkaj60ra05u74g02.jpg" alt="Pasted image 20210906153023" loading="lazy"></figure>
<p>当 k = n 且 n趋向无穷, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>r</mi><mi>a</mi></msub><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">r_a=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span>。当k 很小时，<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>r</mi><mi>p</mi></msub></mrow><annotation encoding="application/x-tex">r_p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> 可能会很大，<strong>因为通信带宽在非colocated PS 中被CPU 机器严重瓶颈</strong>。 例如，当 n = 32 和 k = 16 时，我们分别有 ga = 1.46 和 gp = 1.52。 这意味着 BytePS 理论上可以分别超过 all-reduce 和 PS 46% 和 52%。 我们注意到在 k = n 之外添加更多 CPU 机器无济于事，因为通信瓶颈将成为 GPU 机器的 NIC 带宽。</p>
<h2 id="42-机内通信">4.2 机内通信</h2>
<p>在 §4.1 中，我们设计了最优的机器间通信策略。 在实践中，我们发现机内通信同样重要。 一台机器中通常有多个 GPU。 CS 必须在与 SS 通信之前/之后聚合/广播张量。 这会在 PCIe 链路上造成拥塞，并阻止 NIC 充分利用其带宽 B。此外，GPU 机器的内部拓扑在数据中心可能会有所不同。 下面，我们分享我们环境中最常见的两种机器设置以及我们相应的解决方案。 我们在第 4.2.3 节中介绍了一些适用于其他机器设置的原则。</p>
<h3 id="421-pcie-only-拓扑">4.2.1 PCIe-only 拓扑</h3>
<figure data-type="image" tabindex="7"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kr5ii2jj60vi0ckta702.jpg" alt="Pasted image 20210906154354" loading="lazy"></figure>
<p><em>图 6：仅 PCIe 的机器拓扑和 BytePS 数据流。 灰色框是 GPU。 数据流图中仅显示了传出方向（从 GPU 到网络）。 传入则相反。</em></p>
<p>图 6(a) 显示了我们生产环境中的设置。 一台 GPU 机器有两个通过 QPI 连接的 NUMA CPU。 八个 GPU 分为两组，分别连接到两个 PCIe 交换机。 网卡是 100Gbps 并连接到其中一个 CPU 的 PCIe。 图中所有PCIe链路均为3.0 x16（128Gbps理论带宽）。 CPU 内存和 QPI 具有 &gt; 300Gbps 带宽，通信瓶颈的可能性较小。 我们称之为仅 PCIe 拓扑。对于这个机器模型，我们测量到 GPU 到 GPU 内存复制的吞吐量在同一 PCIe 交换机内为 105Gbps。 然而，跨 PCIe 交换机的 GPU 到 GPU 内存复制的吞吐量仅为 80Gbps。</p>
<p>不幸的是，许多现有的训练框架忽略了内部拓扑的这些细节。 例如，TensorFlow PS、MXNet PS 甚至 Horovod 的“分层 all-reduce”模式在同一台机器上的所有 GPU 上使用直接的 reduce 或 reduce-scatter。 这将导致跨 PCIe 交换机内存复制，不幸的是速度较慢。</p>
<p>相比之下，BytePS让同一PCIe交换机下的GPU先对张量求和，然后复制到CPU让CPU做全局求和，最后广播回全局求和。 我们称之为 CPU 辅助聚合。 具体来说，它包括以下步骤。</p>
<blockquote>
<p>点评：这种做法有点针对特定拓扑吧</p>
</blockquote>
<ol>
<li>Reduce-Scatter：假设每个 PCIe 交换机有L 个 GPU。 这 L 个GPU 执行reduce-scatter，仅在 PCIe 交换机内部产生 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>(</mo><mi>l</mi><mo>−</mo><mn>1</mn><mo>)</mo><mi>M</mi><mi mathvariant="normal">/</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">(l-1)M/l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span></span></span></span> 流量。 当它完成时，每个 GPU 应该保存 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi><mi mathvariant="normal">/</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">M/l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span></span></span></span> 聚合数据。</li>
<li>GPU-CPU 复制：每个 GPU 将其 M/l 数据复制到 CPU 内存，这会导致沿途的 M/l 流量。 每个 PCIe 交换机都会生成 M 个聚合数据。</li>
<li>CPU-Reduce：CPU 规约来自所有 PCIe 交换机的数据并生成跨所有 GPU 的聚合数据。 这种规约不会产生任何 PCIe 流量。</li>
<li>networking：CS 将数据发送到 SS，并从 SS 接收<strong>全局聚合数据</strong>。</li>
<li>CPU-GPU 复制：每个 GPU 将其 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi><mi mathvariant="normal">/</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">M/l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span></span></span></span> 分区从 CPU 内存复制回自身。 这会导致从 CPU 到每个 GPU 的 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>M</mi><mi mathvariant="normal">/</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">M/l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span></span></span></span> 流量。</li>
<li>All-Gather：每个 GPU 对同一 PCIe 交换机下的 GPU 执行all-gather操作。 这会导致交换机内部产生 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>(</mo><mi>l</mi><mo>−</mo><mn>1</mn><mo>)</mo><mi>M</mi><mi mathvariant="normal">/</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">(l-1)M/l</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span></span></span></span>流量。</li>
</ol>
<blockquote>
<p>点评：这个做法比快手使用 0号gpu 的做法要合理一点</p>
</blockquote>
<p>图 6(b) 显示了步骤 1 到 3 的流量。步骤 4 到 6 使用相同的链路但方向相反。 通过 CPU 辅助聚合，从 PCIe 切换到 CPU 链路将在每个方向仅承载 M 个流量，远低于直接在 8 个 GPU 上进行集体操作（7M/4 个流量）。 同时，每个 PCIe 交换机到 GPU 链路的流量将为<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>(</mo><mn>2</mn><mi>l</mi><mo>−</mo><mn>1</mn><mo>)</mo><mi>M</mi><mi mathvariant="normal">/</mi><mi>L</mi></mrow><annotation encoding="application/x-tex">(2l-1)M/L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">2</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord mathdefault" style="margin-right:0.10903em;">M</span><span class="mord">/</span><span class="mord mathdefault">L</span></span></span></span>, 设 l = 4（每个 PCIe 有四个 GPU），即 7M/4，与现有方法保持一致。 从根本上说，BytePS 利用 GPU 机器上的备用 CPU 来避免缓慢的 <strong>GPU 到 GPU 跨 PCIe 交换机内存复制</strong>。</p>
<p><strong>优化分析</strong>。 我们现在分析上述策略的通信最优性。 图 7 显示了一种更通用的仅 PCIe 拓扑，具有可变数量的 GPU 和 PCIe 交换机。 我们没有像图 6(a) 那样绘制 NIC，因为在这种拓扑结构下，NIC 具有专用的 PCIe 通道并且不会与 GPU 竞争 PCIe 带宽。</p>
<figure data-type="image" tabindex="8"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5krr2hlmj60ny0e4mxx02.jpg" alt="Pasted image 20210906164341" loading="lazy"></figure>
<p>系统架构被建模为层次图 G = (V,E)。 将 N 表示为叶节点 (GPU) 的集合，将 S 表示为中间节点（交换机）的集合，将 C 表示为 CPU 节点的集合。 V为 N、S和C的并集. E 中的每条边 e(vx, vy) 表示从顶点 vx 到 vy 的带宽，我们将 t(vx, vy) 表示为从 vx 发送到 vy 的流量。 我们进一步定义 p 为交换机的数量 (p&gt;=2)，n 作为每个交换机连接的叶节点 (n &gt;=2)。</p>
<p>我们假设 G 的以下特征： (1) E 中的每条边都是双工的，并且两个方向的带宽相等。 将b(vx, vy)表示为e(vx, vy)的带宽，则b(vx, vy) = b(vy, vx)； (2) 我们假设 G 是对称的。 树的同一层的带宽是等效的。 例如，对于任何 j, k 属于 [0, p1], x, y 属于 [ jn, (j+1)n-1]; (3)<strong>内存和QPI</strong>带宽远高于PCIe链路，不太可能成为瓶颈。 下面，我们只关注 PCIe 链路。</p>
<blockquote>
<p>补充：<code>QPI &lt;Quick Path Interconnect&gt;</code>，又名CSI，Common System Interface公共系统接口，是一种可以实现芯片间直接互联的架构。</p>
</blockquote>
<p>从 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>N</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">N_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 到 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>N</mi><msub><mi>p</mi><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></msub></msub></mrow><annotation encoding="application/x-tex">N_{p_{n-1}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.975095em;vertical-align:-0.291765em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathdefault mtight">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3173142857142857em;"><span style="top:-2.357em;margin-left:0em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.20252142857142857em;"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.291765em;"><span></span></span></span></span></span></span></span></span></span> 的 GPU 需要对它们的数据求和。 我们可以使用前面提到的 CPU 辅助聚合，也可以使用需要每个 GPU 将其整个数据直接复制到 C 的蛮力复制。 在实践中，最优解应该是这两种策略的组合，取决于 b(Sj,Cj) 和 b(Ni,Sj) 的值。 直觉是我们对 x 的数据应用蛮力复制，并对数据的 y (x+y = 1) 应用 CPU 辅助聚合。 在一定的 x 和 y 下，作业完成时间 J 可以最小化。 我们分别计算两条链路的流量。 在 e(Sj,Cj) 上，流量由 n 次蛮力复制加上 CPU 辅助聚合的流量组成。 在 e(Ni,Cj) 上，流量由一个蛮力副本和 CPU 辅助聚合的完整流量组成。</p>
<blockquote>
<p>这里其实没明白为什么</p>
</blockquote>
<figure data-type="image" tabindex="9"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5ksbqn8lj60vw09cgma02.jpg" alt="Pasted image 20210906172651" loading="lazy"></figure>
<p>（一通计算后）这意味着最佳解决方案是这样工作的：每个 GPU 对其 1/5 数据应用蛮力复制，并对其余 4/5 数据使用 CPU 辅助聚合。 因此，我们有以下主要结论：</p>
<p><strong>CPU 辅助聚合接近最佳</strong><br>
当 x = 0 时，解决方案是我们的 CPU 辅助聚合，作业完成时间为 J(0) = 0.141s。 根据计算，最佳时间为 0.129 秒。 因此，我们的策略非常接近最佳解决方案，性能差异为 9%。 然而，在实践中，强力复制对 CPU 内存有很大压力——与 CPU 辅助聚合相比，任何使用强力复制的张量都将消耗 4倍 CPU 内存带宽。 CPU内存真的没有4倍带宽的PCIe链路，尤其是FP16求和。因此，我们选择根本不使用蛮力复制并坚持使用 CPU 辅助聚合。</p>
<p><strong>CPU 辅助聚合优于基于环的 allreduce</strong></p>
<figure data-type="image" tabindex="10"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kssysyxj60w8076gn102.jpg" alt="Pasted image 20210906173540" loading="lazy"></figure>
<p>所以很容易证明 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>J</mi><mrow><mi>c</mi><mi>a</mi></mrow></msub><mo>&lt;</mo><msub><mi>J</mi><mrow><mi>a</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">J_{ca} &lt; J_{ar}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.09618em;">J</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.09618em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">c</span><span class="mord mathdefault mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.09618em;">J</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.09618em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">a</span><span class="mord mathdefault mtight" style="margin-right:0.02778em;">r</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 对于任何 n, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>p</mi><mo>&gt;</mo><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">p&gt;=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335400000000001em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 总是成立。例如，使用我们的 PCIe 机器的值，让 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>p</mi><mo>=</mo><mn>2</mn><mo separator="true">,</mo><mi>n</mi><mo>=</mo><mn>4</mn><mo separator="true">,</mo><msub><mi>b</mi><mrow><mi>b</mi><mi>o</mi><mi>t</mi><mi>t</mi><mi>l</mi><mi>e</mi><mi>n</mi><mi>e</mi><mi>c</mi><mi>k</mi></mrow></msub><mo>=</mo><mn>80</mn><mi>G</mi><mi>b</mi><mi>p</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">p = 2, n = 4, b_{bottleneck} = 80Gbps</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8388800000000001em;vertical-align:-0.19444em;"></span><span class="mord">2</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">4</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">b</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.33610799999999996em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">b</span><span class="mord mathdefault mtight">o</span><span class="mord mathdefault mtight">t</span><span class="mord mathdefault mtight">t</span><span class="mord mathdefault mtight" style="margin-right:0.01968em;">l</span><span class="mord mathdefault mtight">e</span><span class="mord mathdefault mtight">n</span><span class="mord mathdefault mtight">e</span><span class="mord mathdefault mtight">c</span><span class="mord mathdefault mtight" style="margin-right:0.03148em;">k</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">8</span><span class="mord">0</span><span class="mord mathdefault">G</span><span class="mord mathdefault">b</span><span class="mord mathdefault">p</span><span class="mord mathdefault">s</span></span></span></span>（跨越 PCIe 交换机的内存副本的带宽 ) 和 b(Sj,Cj) = 105Gbps 我们得到 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>J</mi><mrow><mi>c</mi><mi>a</mi></mrow></msub></mrow><annotation encoding="application/x-tex">J_{ca}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.09618em;">J</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.09618em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">c</span><span class="mord mathdefault mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 比 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>J</mi><mrow><mi>a</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">J_{ar}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.09618em;">J</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.09618em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">a</span><span class="mord mathdefault mtight" style="margin-right:0.02778em;">r</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 小 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>23.7</mn></mrow><annotation encoding="application/x-tex">23.7%</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">3</span><span class="mord">.</span><span class="mord">7</span></span></span></span>。</p>
<h3 id="422-基于-nvlink-的拓扑">4.2.2 基于 NVLink 的拓扑</h3>
<p>图 8(a) 显示了我们数据中心的另一个机器模型——带有 NVLinks 的 GPU 机器。 有四个 PCIe 交换机，每个交换机连接两个 GPU 卡。 GPU 也通过 NVLink 连接。 NVLinks 为每个 GPU 提供总计 1.2Tbps GPU-GPU 带宽，远高于 PCIe 链路。 NIC 连接到其中一个 PCIe 交换机。</p>
<figure data-type="image" tabindex="11"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5ktg0ciuj60w80es76302.jpg" alt="Pasted image 20210906193948" loading="lazy"></figure>
<p><em>图 8：基于 NVLink 的机器拓扑和 BytePS 数据流。 数据流图中只显示出方向</em></p>
<p>有了NVLink，GPU-to-GPU通信可以完全避免占用PCIe带宽。 因此，我们不再需要 CPU 辅助聚合。 然而，我们发现现有框架，包括最流行的 GPU all-reduce 实现 NCCL（由 TensorFlow、PyTorch、MXNet 和 Horovod 使用），再次不是最佳的。</p>
<p>问题在于，考虑到 NIC，拓扑不对称，它仅连接到一个（四分之一）PCIe 交换机。 同一个PCIe交换机下的网卡和两个GPU要争夺 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>0</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_0-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 的PCIe带宽。 请记住，不仅 CS 使用此 PCIe 带宽，而且在同一台 GPU 机器上运行的 SS 也使用它！ <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>0</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_0-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 再次成为整个通信的瓶颈。</p>
<p>根据分析，我们应该在本地聚合时将尽可能多的<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>0</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_0-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> PCIe带宽留给网卡。 对于这种拓扑，BytePS 使用reduce 和broadcast 而不是reduce-scatter 和all-gather——来自所有GPU 的张量首先 reduce 到GPU2，然后将结果从 GPU2 复制到CPU0 内存。 图 8(b) 显示了这些步骤。 之后，当 CS 从 SS 得到聚合结果时，GPU2 会将数据复制到 GPU 内存中，并将它们广播到其他 GPU。 这样，我们完全阻止了 GPU 使用 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>0</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_0-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 带宽进行通信，因此 NIC 可以运行到 100Gbps 带宽。</p>
<blockquote>
<p>点评：这个拓扑的bug 在于gpu 连接是一个环，建立在特殊的拓扑基础上。<br>
从内存拷贝到网卡用PCIE， 网线会是另外的瓶颈</p>
</blockquote>
<p>这种方法似乎会在 GPU2 上创建流量热点。 但是，NVLinks 的带宽比 PCIe 链路大得多，因此即使在热点上，GPU 间通信也永远不是瓶颈。 同时，用于GPU-CPU复制的<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>1</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_1-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>  PCIe链路与网卡100Gbps带宽大致相同，因此也不是瓶颈。</p>
<p>BytePS 达到了最优结果——没有机内带宽瓶颈。 不幸的是，现有的解决方案，如 NCCL，由于 GPU0 和 NIC 之间的距离很近，往往让 GPU 使用 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mn>0</mn></msub><mo>−</mo><mi>C</mi><mi>P</mi><msub><mi>U</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">P_0-CPU_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.10903em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 瓶颈链路。</p>
<p>因此，它的通信性能低于我们在基于 NVLink 的机器中的解决方案。</p>
<blockquote>
<p>点评：这个看起来应该只是一个微小的工作吧</p>
</blockquote>
<h3 id="423-讨论">4.2.3 讨论</h3>
<p>PCIe-only 和基于 NVLink 拓扑的解决方案大不相同。 这表明不存在万能的最优解。 <strong>匹配内部通信必须适应不同的内部拓扑</strong>。 诚然，在我们的环境中使用的拓扑肯定比上述两种更多。 但是，我们认为以上两个是具有代表性的，因为它们分别类似于服务器供应商和 NVIDIA推荐的参考设计。</p>
<p>尽管存在差异，但我们总结了两个原则 - 1）当两个 GPU 不在同一个 PCIe 交换机下时，始终避免直接 GPU 到 GPU 内存复制，因为它在实践中很慢。 2) 始终尽量减少 PCIe 交换机到 GPU 和 NIC 共享的 CPU 链路上的流量。 我们提出以下最佳实践程序。 设 Sn 是带有 GPU 和 NIC 的 PCIe 交换机的数量，Sg 是只有 GPU 的 PCIe 交换机的数量。</p>
<ol>
<li>如果 Sn &gt; 0 且 Sg &gt; 0，则拓扑是非对称的，就像我们基于 NVLink 的拓扑一样。 CS 应该使用reduce 和broadcast，使用不与NIC 竞争的GPU 作为reduce 或broadcast 根。</li>
<li>如果 Sn = 0 或 Sg = 0，拓扑是对称的，就像我们的 PCIe-only 情况一样。 CS 应该使用 reduce-scatter 和 allgather 来平衡所有 PCIe 交换机上的流量。 如果没有 NVLink，则应使用 CPU 辅助聚合（第 4.2.1 节）。</li>
</ol>
<p><strong>多网卡拓扑</strong>。 虽然我们讨论的两种具体拓扑只有一个网卡，但上述原理可以直接扩展到多网卡拓扑——它只是改变了 Sn 和 Sg 的值。</p>
<p><strong>GPU 直接 RDMA (GDR)</strong>。 GDR 可以潜在地减少 PCIe 流量。 但是，GDR 要求 GPU 和 RDMA 网卡在同一个 PCIe 交换机上，否则即使使用 100GbE 网卡，吞吐量也可能低于 50Gbps [12]，我们自己的测量也证实了这一点。 因此，GDR 对我们的设置没有好处——仅 PCIe 拓扑不能满足要求，我们已经避免了基于 NVLink 拓扑的任何 PCIe 瓶颈。 此外，像 AWS 这样的大多数云都不支持 GDR。 因此，BytePS 目前不使用 GDR。</p>
<blockquote>
<p>点评：byteps 不支持 GPU 直接RDMA</p>
</blockquote>
<p>我们可以看到最优的<strong>机内通信策略与内部拓扑紧密耦合</strong>。 构建一个分析器来自动检测拓扑、探测带宽并生成最佳策略是未来有趣的工作。</p>
<h1 id="5-求和服务">5 求和服务</h1>
<p>为了获得最佳的机器间通信时间（第 4.1 节），BytePS 需要一个可以在每台机器的 CPU 上运行并与 CS 通信的模块。 问题是，它在训练算法中的作用是什么？ 我们最初的尝试是遵循之前的 PS 设计，其中 PS 进程负责运行优化器。 优化器聚合来自所有 GPU 的梯度，并使用各种优化器更新 DNN 模型参数。</p>
<h2 id="cpu-瓶颈">CPU 瓶颈</h2>
<p>不幸的是，很快我们发现 CPU 成为系统中的瓶颈。 我们用一个实验来证明这一点。 我们使用典型的非协同 PS 设置训练 VGG16 DNN ：使用一台 Tesla V100 GPU 机器和一台 CPU 机器（Intel Xeon Platinum CPU，具有超线程的 32 核和 Intel MKL ），通过 100GbE 以太网连接 . GPU 机器运行前向和反向传播，CPU 机器使用全部 32 个 CPU 内核运行优化器。</p>
<figure data-type="image" tabindex="12"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5ktx6e3rj60ww0e876a02.jpg" alt="Pasted image 20210906204431" loading="lazy"></figure>
<p><em>图 9：优化器的 CPU 很慢，但求和的 CPU 不慢</em></p>
<p>图 9(a) 显示，即使有 32 个内核并启用了 MKL，在 CPU 机器上运行优化器也会减慢端到端的训练速度。 这意味着 CPU 无法匹配网络带宽并成为瓶颈（第 6 节）。 随着优化器算法变得越来越复杂（从更简单的 SGD 到更复杂的 RMSProp），瓶颈效应变得更加严重。</p>
<p>根本原因。 CPU 瓶颈是由有限的内存带宽引起的。 Adam 等流行的优化器很容易耗尽现代 CPU 的内存带宽。 例如，6 通道 DDR4-2666 内存设置的峰值传输速率高达 1024 Gbps，结合读取和写入 [8]。 很容易估计，例如，Adam 优化器 [42] 需要超过 10 倍的内存访问（读+写）来应用每个梯度更新。 加上 100Gbps 网卡消耗 200 Gbps 内存带宽（读+写），1024 Gbps 内存带宽根本不足以让 Adam 处理 100 Gbps 梯度流。</p>
<blockquote>
<p>点评：这里很硬核</p>
</blockquote>
<h2 id="cpu擅长求和">CPU擅长求和</h2>
<p>上面的实验让我们重新思考 CPU 上的任务。优化器的计算可以分为两个步骤，梯度求和和参数更新，如图 10 所示。</p>
<figure data-type="image" tabindex="13"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kufwhl2j60v20ay0u502.jpg" alt="Pasted image 20210906205041" loading="lazy"></figure>
<p><em>图 10：all-reduce、PS 和 BytePS 之间的组件放置比较</em></p>
<p>幸运的是，由于高度优化的<strong>AVX 指令 [47]</strong>，现代 x86 CPU 擅长求和。 在图 9(b) 中，我们使用合成浮点张量显示了与上述相同 CPU 上的求和吞吐量。 <strong>FP16和FP32精度的吞吐量都超过200Gbps，高于100Gbps的网卡带宽</strong>。 因此，CPU 上的求和不会成为瓶颈。</p>
<p>BytePS 的解决方案。 基于这些观察，BytePS 将优化器的两个步骤解耦。 我们将计算密集型参数更新移至 GPU，并仅在 CPU 上进行求和——这就是我们将 CPU 模块命名为求和服务 (SS) 的原因。 SS 不仅可以避免 CPU 成为瓶颈，还可以大大降低 CPU 开销。 通过使用 AVX 和 OpenMP 精心实施，SS 在以 100Gbps 吞吐量运行时仅消耗少于 3 个 CPU 内核。 图 10 对 PS、all-reduce 和 BytePS 进行了high-level 比较，了解它们如何将 DNN 训练中的不同组件放置到 GPU 和 CPU 资源上。</p>
<p>由于 Summation Service 将参数更新移动到 GPU 机器上，因此所有 GPU 机器都需要执行相同的参数更新计算，而在传统 PS 中，参数更新只需进行一次。 因此，BytePS 比 PS 使用更多的计算周期来更新参数。 这是我们自愿做出的权衡，以加快端到端的训练速度。 我们将 SS 开销比定义为 参数更新的 FLOP 除以FP 和 BP FLOPS 总和。</p>
<p>VGG-16、ResNet-50、BERTlarge使用SGD作为优化器的比率为138 MFLOPs / 32 GFLOPs、26 MFLOPs / 7.8 GFLOPs、387 MFLOPs / 494 GFLOPs，<strong>均小于0.5%</strong>。 与训练加速相比，引入的开销可以忽略不计（图 9（a））。 上述比率定义假设批量大小为 1。DNN 训练通常使用数十或数百个批量大小。 每批参数更新一次，因此额外的开销在实践中更小。</p>
<p>我们注意到 Horovod [60] 可以选择通过首先将张量复制到 CPU 内存然后执行 CPU-only all-reduce 来将梯度聚合移动到 CPU。 由于它仍然只依赖 GPU 机器上的 CPU 和带宽，因此与 GPU 上的直接 all-reduce 相比，它没有提供通信方面的优势。 BytePS 不同：它利用额外的 CPU 机器进行梯度求和，同时在 GPU 上保持参数更新。</p>
<blockquote>
<p>点评：byteps 用的额外的cpu 和带宽</p>
</blockquote>
<h2 id="支持异步训练">支持异步训练</h2>
<p>虽然分离求和和更新给我们带来了性能上的好处，但它打破了原始 PS 的一个重要特性：像 Asynchronous Parallel [25] 这样的异步训练的支持。 异步并行依赖于保持最新模型参数的 PS 进程，这与 SS 的设计不直接兼容。</p>
<blockquote>
<p>点评：是啊，worker 上做参数更新，那肯定得同步更新</p>
</blockquote>
<p>为了弥补这一差距，我们重新设计了一个新的工作流程，可以启用与 SS 的异步训练，如图 11（b）所示。 简而言之，GPU 更新参数并首先计算 delta 参数。 CS 发送它们并接收最新的参数。 SS 不断地在最新的参数中添加 delta 参数。 接下来，我们证明这个新的训练工作流程在算法收敛方面等同于异步并行。</p>
<figure data-type="image" tabindex="14"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kv3ivedj60qo0aodgz02.jpg" alt="Pasted image 20210906215412" loading="lazy"></figure>
<p>图 11：PS 和 BytePS 之间的异步训练工作流比较。 g 是梯度。 w 是参数。</p>
<p><strong>定理2</strong> BytePS的异步算法等价于异步并行<br>
<strong>证明</strong>  考虑一个与 n 个 CS 相连的 SS。 我们说 CS 存储本地模型参数，SS 保存最新版本的参数。 我们证明的high level 想法是表明，在给定相同的通信顺序（推和拉顺序）的情况下，我们的算法与异步并行生成相同的状态（即，SS 模块和 n 个 CS 模块的相同参数）。 我们使用 f 作为优化器的一般表示。因此，优化可以表示为 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>w</mi><mo>=</mo><mi>w</mi><mo>+</mo><mi>f</mi><mo>(</mo><mi>g</mi><mi>i</mi><mo separator="true">,</mo><mi>t</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">w=w+ f(gi,t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.03588em;">g</span><span class="mord mathdefault">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">t</span><span class="mclose">)</span></span></span></span>，其中 gi,t 表示迭代 t (t  in [1,T]) 时 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>C</mi><msub><mi>S</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">CS_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.07153em;">C</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> (i  in [0,n1]) 的梯度。 分别将 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>w</mi><mrow><mi>p</mi><mi>s</mi></mrow></msub></mrow><annotation encoding="application/x-tex">w_{ps}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.02691em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">p</span><span class="mord mathdefault mtight">s</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>w</mi><mrow><mi>b</mi><mi>y</mi><mi>t</mi><mi>e</mi><mi>p</mi><mi>s</mi></mrow></msub></mrow><annotation encoding="application/x-tex">w_{byteps}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.02691em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">b</span><span class="mord mathdefault mtight" style="margin-right:0.03588em;">y</span><span class="mord mathdefault mtight">t</span><span class="mord mathdefault mtight">e</span><span class="mord mathdefault mtight">p</span><span class="mord mathdefault mtight">s</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> 表示为 PS 和 BytePS 中的参数。 并且将 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>w</mi><mrow><mi>i</mi><mo separator="true">,</mo><mi>t</mi></mrow></msub></mrow><annotation encoding="application/x-tex">w_{i,t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.311664em;"><span style="top:-2.5500000000000003em;margin-left:-0.02691em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">i</span><span class="mpunct mtight">,</span><span class="mord mathdefault mtight">t</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> 表示为迭代 t 时每个 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>w</mi><mi>o</mi><mi>r</mi><mi>k</mi><mi>e</mi><msub><mi>r</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">worker_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord mathdefault" style="margin-right:0.02691em;">w</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="mord mathdefault" style="margin-right:0.03148em;">k</span><span class="mord mathdefault">e</span><span class="mord"><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>（对于 PS）或 CS（对于 BytePS）上的参数。 对于所有 CS 和 SS，该参数被初始化为 w0。 经过 T 次迭代，我们可以得到更新后的参数为：</p>
<figure data-type="image" tabindex="15"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kxlas4dj614q09gmxm02.jpg" alt="Pasted image 20210906220857" loading="lazy"></figure>
<blockquote>
<p>点评：这个证明其实没有谈到异步时间的问题</p>
</blockquote>
<h1 id="6-实现">6 实现</h1>
<p>虽然 BytePS 的核心对于任何训练框架都是通用的，但 BytePS 还为 TensorFlow、PyTorch 和 MXNet 实现了插件，以方便用户使用。 核心是用 C++ 实现的，而框架插件包含 C++ 和 Python。 BytePS 总共包含大约 7.8K 行 Python 代码和 10K 行 C++ 代码。 作为主要的在线服务提供商，我们在内部部署了 BytePS。 BytePS 也已经开源 [4] 并吸引了成千上万的用户。</p>
<h2 id="61-多阶段流水线">6.1 多阶段流水线</h2>
<p>加速多步骤过程的一种常见方法是构建一个多级流水线，该流水线与每个步骤的处理时间重叠。 我们结合了先前工作中的张量分区和流水线的想法 [34, 55]。 例如，对于 PCIe-only 拓扑，CS 有六个步骤。 它映射到 <strong>BytePS 运行时</strong>中的 6 级管道。 我们实现 BytePS 以灵活构建管道而无需重新编译。 管道中的每个阶段都被实现为一个具有张量优先级队列的独立线程。 优先级的分配类似于 [34,55]。 正如 §4.1.1 中分析的那样，大张量被分割成多个不超过 4MB 的小张量。 接下来，每个小张量被排入第一个队列，并在一个阶段完成处理后移向下一个队列，直到它从最后一个队列中出列。</p>
<h2 id="62-解决-rdma-性能问题">6.2 解决 RDMA 性能问题</h2>
<p>对于机器间通信，我们使用 RDMA RoCEv2。 每台机器有一个 100GbE 网卡，RDMA 网络提供完整的双向带宽。 为了充分发挥 RDMA 的优势，我们经历了完整的设计和调试之旅，我们分享如下。</p>
<p><strong>RDMA 内存管理</strong></p>
<p>为了提高性能，我们的目标是避免不必要的内存复制 [72] 并在 CPU 内存上实现零复制。 BytePS 基于 RDMA WRITE，因为它是常见 RDMA 用法中性能最高的 [39]。</p>
<blockquote>
<p>点评：RDMA这些论文也看看</p>
</blockquote>
<p>传统的单边 RDMA 操作（WRITE 和 READ）至少需要两次往返：获取远程地址，并将值写入（读取）到（从）该地址 [39, 40, 50, 70]。 我们通过利用 DNN 训练在每次迭代中始终发送相同的张量集这一事实来优化过程。传统的单边 RDMA 操作（WRITE 和 READ）至少需要两次往返：获取远程地址，并将值写入（读取）到（从）该地址 [39, 40, 50, 70]。 我们通过利用 <strong>DNN 训练在每次迭代中始终发送相同的张量集这一事实</strong>来优化过程。</p>
<blockquote>
<p>点评：也就是寻址只需要一次，那特征准入没发解决吧</p>
</blockquote>
<p>只有在第一次迭代时，BytePS 才会初始化所有需要的张量，向 RDMA NIC 注册缓冲区并交换所有远程地址。 然后 BytePS 存储远程缓冲区信息并在其余迭代中直接重用。</p>
<blockquote>
<p>点评：也就是用空间换时间，多占M的空间</p>
</blockquote>
<p><strong>解决慢速接收器症状</strong><br>
我们还遇到了 [30] 中报告的缓慢接收器症状——NIC 向网络发送了许多 PFC。 那些过多的 PFC 会减慢张量传输速度，这可能会对其他流量造成附带损害。 在这里，我们报告了这种症状的几个其他原因以及我们如何解决这些问题</p>
<p>我们的第一个发现是内部 RDMA 环回流量会导致内部 incast，并推动 NIC 生成 PFC。 BytePS 在每台 GPU 机器上运行 CS 和 SS。 它们之间的流量，我们称之为环回流量，不消耗 NIC 的外部以太网带宽，但会消耗内部 CPU-NIC PCIe 带宽。 最初，我们没有添加任何特殊设计——我们坚持使用 RDMA  [9] 来处理环回流量，并认为 NIC DMA 可以处理它。 但是，我们意识到它在 NIC 上创建了 2:1 的 incast，将 RX 和环回作为两个入口端口，将 DMA 到内存引擎作为一个出口端口！</p>
<blockquote>
<p>点评：不太理解这段</p>
</blockquote>
<p>为了解决这个问题，我们实现了一个共享内存 (shm) 数据路径。 当 CS 检测到 SS 与自己在同一台机器上时，CS 会简单地通知 SS 数据在共享内存中。 SS完成求和后，SS将结果从自己的缓冲区复制回CS的共享内存。 因此，消除了环回 RDMA 流量。</p>
<blockquote>
<p>点评：使用共享内存代替socket，正常做法，local 不用rdma</p>
</blockquote>
<p>我们的第二个发现是我们需要为 RDMA 使用页面对齐的内存。 否则可能会触发 PFC。 我们的假设是硬件 DMA 将传输单元与页面大小（例如 4096 字节）对齐。 因此，<strong>使用页对齐地址对 DMA 引擎更友好，因为它减少了需要写入的页数</strong>。</p>
<p>我们的第三个发现是，RDMA NIC RX 性能会受到<strong>并发</strong>发送的实现方式的影响！ 最后，我们不仅使用页面对齐的内存，而且在发送方的每个 RDMA WRITE 只强制执行一个scater-gather entry (sge)。</p>
<p>在整个过程中，我们联系了网卡供应商，并与他们的软硬件专家进行了长时间的讨论。 在撰写本文时，我们还没有得到最后两个问题的官方根本原因。</p>
<p>在所有优化之后，BytePS 实现可以按预期运行。 表 2 显示了应用上述三种优化中的每一种后的性能改进。 NIC 产生的 PFC 可忽略不计。</p>
<blockquote>
<p>点评：相当于byteps硬核修改了 rdma的实现？</p>
</blockquote>
<figure data-type="image" tabindex="16"><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gv5kyusj8dj612009w40202.jpg" alt="Pasted image 20210907094705" loading="lazy"></figure>
<p>正如我们在 §4.1 中所讨论的，BytePS 在网络中创建了许多多对一的通信模式。 多对一以在 TCP/IP 网络中创建 incast 和丢包而闻名 [66]。 但是 BytePS 使用 RDMA/RoCEv2，它依赖于无损结构和 DCQCN [75] 进行拥塞控制。 我们在 BytePS 中没有观察到 incast 问题。</p>
<blockquote>
<p>点评：<a href="https://www.cnblogs.com/liusikun/p/5663193.html">tcp incast 问题</a></p>
</blockquote>
<h2 id="63-byteps-的使用">6.3 BytePS 的使用</h2>
<p>BytePS易于使用。 我们提供几乎与 Horovod、PyTorch 原生 API 和 TensorFlow 原生 API 相同的 Python 接口。 用户可以选择其中任何一个，并以最小的努力迁移到 BytePS。 例如，对于 Horovod-MNIST 示例，我们只需要更改一行 Python 代码，从“import horovod”到“import byteps”。 事实上，我们能够将大部分基于 Horovod 的内部训练任务自动转换为 BytePS。</p>
<h1 id="7-evaluation">7. Evaluation</h1>
<p>在本节中，我们展示了 BytePS 不仅在微基准测试中实现了最佳通信性能，而且还显着加速了生产环境中的训练工作。 我们列出了一些关于结果高保真度的亮点.</p>
<ul>
<li>所有使用的资源都由生产集群的调度器分配。调度器使用非抢占式资源调度——一旦调度了一个训练作业，它将拥有固定数量的 CPU 机器，不会改变。即使是我们展示的最大规模的任务，也使用运行许多生产任务的集群的不到 5% 的 GPU。</li>
<li>我们使用大的训练批次大小。<strong>较小的批大小意味着更少的 GPU 内存消耗但更多的通信</strong>，因此端到端的改进将更加明显。然而，我们所有的任务几乎都使用了 GPU 内存，因此针对 all-reduce 和 PS 的加速数字是 BytePS 的下限。</li>
<li>虽然我们不能透露任何内部使用的具体模型，但显示的任务和 DNN 模型结构高度代表了生产工作负载。该代码也可公开获取以实现可重复性。</li>
<li>我们将BytePS 与最先进的PS 和allreduce 实现进行比较，无需修改。例如，我们不会将 §6.2 中提到的 RDMA 优化应用于 native-PS 和 all-reduce</li>
</ul>
<p>我们使用的集群有一个全二分带宽的 RoCEv2 网络。 所有机器都有一个 100GbE 网卡。 我们注意到 TensorFlow、PyTorch 和 MXNet 可以重叠 DNN 计算和通信 [34, 55]，因此即使端到端性能的微小改进也可以表明通信的巨大改进。</p>
<blockquote>
<p>点评：这里说的应该是非稀疏场景的情况</p>
</blockquote>
<blockquote>
<p>补充：<strong>Ro****CE</strong>是在InfiniBand Trade Association（IBTA）标准中定义的<strong>网络</strong>协议，允许通过以太网络使用RDMA。<br>
大致有三类RDMA网络，分别是Infiniband、RoCE、iWARP。其中，Infiniband是一种专为RDMA设计的网络，从硬件级别保证可靠传输 ，而RoCE 和 iWARP都是基于以太网的RDMA技术，支持相应的verbs接口。<br>
<a href="https://cloud.tencent.com/developer/article/1771431">浅析RoCE网络技术 - 云+社区 - 腾讯云</a></p>
</blockquote>
<h1 id="8-观察与讨论">8. 观察与讨论</h1>
<p>在本节中，我们将分享我们的一些观察和讨论，旨在激发未来的研究。</p>
<p>即使没有额外的 CPU 机器，BytePS 的性能也优于 all-reduce。 理论上，当没有额外的 CPU 机器可用时，all-reduce 和 BytePS 的通信时间是相同的（第 4.1 节）。 在实践中，我们观察到 BytePS 在这种情况下仍然明显优于 all-reduce。 一个原因是 BytePS 有比 all-reduce 更好的机内通信策略。 然而，即使没有机器内优化，BytePS 仍然优于 all-reduce。</p>
<p>我们假设 BytePS 比 all-reduce 具有允许更多“异步性”的优势。 All-reduce 通常需要额外的带外同步来保证跨节点的顺序一致，而 BytePS 没有这个开销。 然而，为了分析它，我们需要一个分布式分析器，它可以构建分布式训练中跨所有节点的执行和通信的完整时间线</p>
<blockquote>
<p>点评：确实没有看到在cpu上进行同步的情况</p>
</blockquote>
<p>GPU 集群调度器应该考虑动态 CPU 资源。 通过利用额外的 CPU 机器，BytePS 可以加速 DNN 训练。 由于 BytePS 可以适应任意数量的 CPU 机器，因此它具有弹性——集群调度程序可以根据实时条件为现有作业扩展或缩减 CPU 机器。 由于收敛问题[16, 74]，大多数现有的调度器将作业的 GPU 数量保持不变。 幸运的是，BytePS 中的 CPU 机器数量只影响系统性能，而不影响模型收敛。 我们计划为 BytePS 添加弹性支持，这将使 BytePS 在训练过程中动态调度 CPU 资源。</p>
<blockquote>
<p>点评：弹性调度，但是hash 索引要变，可能这里利用一致性hash</p>
</blockquote>
<p>模型并行支持。 当减少跨 GPU 的张量时，BytePS 可以加速通信。 一些模型并行方法，例如 Megatron-LM  和 MeshTensorFlow ，也依赖于 all-reduce 原语进行通信。 因此，BytePS 也可以通过替换 all-reduce 操作来加速它们。</p>
<h1 id="9-related-work">9 Related Work</h1>
<p><strong>计算加速</strong>：<br>
为了加速前向传播和反向传播，社区已经制定了许多先进的编译器和库，包括 cuDNN [10]、MKL [7]、TVM [23]、XLA [17]、Astra [64] 和其他计算图优化，例如张量融合 [14] 和图替换 [37]。 他们专注于加速 DNN 计算。 它们是 BytePS 的补充并可与 BytePS 一起使用。</p>
<blockquote>
<p>点评：与社区兼容是很重要的一点</p>
</blockquote>
<p><strong>通信加速</strong>：<br>
加速通信有几个方向：（1）梯度压缩[21, 45]被提出来减少通信流量，即使用半精度进行梯度传输，代价是潜在的精度下降。 (2) 通信调度和流水线：最近的工作探索通过基于优先级的调度和张量分区来更好地重叠计算和通信 [31, 34, 55]。 想法是张量分区可以同时进行双向通信，并且在通信期间，前几层具有更高的优先级，因为下一次迭代的 FP 需要更快地使用它们。 这些想法是对 BytePS 的补充，并且它们已集成到我们的实现中。 Pipedream [51] 增加了多个批次之间的并行性。 BytePS 还可以潜在地加速其数据并行阶段。</p>
<blockquote>
<p>点评：快手也用了梯度压缩，介绍说精度不下降</p>
</blockquote>
<p><strong>分层 all-reduce</strong>：<br>
一些工作建议在 all-reduce 期间利用分层拓扑 [24, 49]，以最小化瓶颈链接处的流量。 然而，他们仍然依赖于资源同质的假设，而忽略了 CPU 资源。 BytePS 可以通过利用异构资源来超越它们。 其实最新的NCCL包括了分层的、基于树的all-reduce，和结果差别不大。</p>
<p><strong>机内优化</strong>：Blink [68] 还通过利用 NVLinks 和 PCIe 链路上的混合传输优化了单台机器内的多个 GPU 通信。 但是，Blink 没有优化分布式训练案例，其中主要的通信瓶颈是 NIC 及其 PCIe 连接，而不是速度更快的 NVLink。 BytePS 仔细调度机器内流量以更好地利用瓶颈带宽——网卡带宽。 我们的机内设计也考虑了网卡消耗的 PCIe 带宽，而 Blink 只关注 GPU 的 PCIe 连接。</p>
<blockquote>
<p>补充：利用 GPU 间所有异构数据传输通道，实现数据聚合的最优解决方案 Blink。相比 NCCL/Horovod，Blink 提高 GPU 间数据聚合的通信效率高达 8 倍，最多可以缩短分布式机器学习模型总训练时间的 40%<br>
<a href="https://blog.csdn.net/danteLiujie/article/details/102901189">Blink:网络自适配的GPU集群通信库 - 深度学习集群_danteLiujie的专栏-CSDN博客</a></p>
</blockquote>
<p><strong>用于加速 DNN 训练的新硬件芯片或架构</strong>：<br>
最近有许多新芯片，如 TPU [38] 和 Habana [6]，专门用于 DNN 训练。 事实上，BytePS 的设计并不是针对 GPU 的，只要它们也是 PCIe 设备就应该适用于它们。 有些人还建议使用 InfiniBand 交换机 ASIC [28] 来加速 all-reduce，或使用 P4 交换机 [58, 59] 来加速 PS。 E3 [46] 利用 SmartNIC 来加速网络应用程序，并且可以通过将梯度求和从 CPU 卸载到 SmartNIC 来潜在地使 BytePS 受益。 PHub [48] 提出了一种具有定制网络配置的机架级硬件架构，例如，一台服务器上有 10 个 NIC。 BytePS 专注于在商品数据中心使用普遍可用的 CPU 和 GPU 服务器。</p>
<h1 id="10-结论">10 结论</h1>
<p>BytePS 是一个统一的分布式 DNN 训练加速系统，可在异构 GPU/CPU 集群中实现最佳通信效率。 BytePS 处理不同数量的 CPU 机器的情况，并将传统的 all-reduce 和 PS 作为其框架的两个特殊情况。 为了进一步加速 DNN 训练，<strong>BytePS 提出了 Summation Service，并将 DNN 优化器拆分为两部分：梯度求和和参数更新。</strong> 它将 CPU 友好的部分，梯度求和保留在 CPU 中，并将计算量更大的参数更新移动到 GPU。 我们已经实施了 BytePS 并解决了许多实施问题，包括<strong>影响 RDMA 性能的问题</strong>。 BytePS 已被部署、广泛使用和开源 [4]。 已经基于它开发了多个外部项目。 重现评估的工件附录位于 [3]。</p>
<!-- more -->

          </div>
        </div>

        
          <div class="next-post">
            <a class="purple-link" href="https://dragonfive.gitee.io/post/bai-du-de-lesslessaibox-ctr-prediction-model-training-on-a-single-nodegreatergreater/">
              <h3 class="post-title">
                下一篇：百度的《AIBox: CTR Prediction Model Training on a Single Node》
              </h3>
            </a>
          </div>
          
      </div>

      

      <div class="site-footer">
  <div class="slogan">邮箱(base64)：MTY5MDMwMjk2M0BxcS5jb20=
</div>
  <div class="social-container">
    
      
        <a href="https://github.com/DragonFive" target="_blank">
          <i class="fab fa-github"></i>
        </a>
      
    
      
    
      
    
      
    
      
    
  </div>
  Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a> | <a class="rss" href="https://dragonfive.gitee.io//atom.xml" target="_blank">RSS</a>
</div>


    </div>
    <script type="application/javascript">

hljs.initHighlightingOnLoad()

var app = new Vue({
  el: '#app',
  data: {
    menuVisible: false,
  },
})

</script>




  </body>
</html>
